<?PHP
#
#   FILE:  SysConfig.php
#
#   Part of the Metavus digital collections platform
#   Copyright 2017-2021 Edward Almasy and Internet Scout Research Group
#   http://metavus.net
#

use Metavus\FormUI;
use Metavus\MetadataSchema;
use Metavus\PrivilegeFactory;
use Metavus\SystemConfiguration;
use Metavus\User;
use Metavus\UserFactory;
use ScoutLib\ApplicationFramework;
use ScoutLib\StdLib;

# ----- LOCAL FUNCTIONS ------------------------------------------------------

/**
* Define fields for form.
* @return array Associative array of form field parameters, in the format
*       expected by FormUI.
*/
function DefineFormFields()
{
    # load up possible values for SearchEngineUpdatePriority and
    #       RecommenderEngineUpdatePriority settings
    $PFactory = new PrivilegeFactory();
    $TaskPriorities = [
        ApplicationFramework::PRIORITY_BACKGROUND => "Background",
        ApplicationFramework::PRIORITY_LOW => "Low",
        ApplicationFramework::PRIORITY_MEDIUM => "Medium",
        ApplicationFramework::PRIORITY_HIGH => "High"
    ];

    $ResourceSchema = new MetadataSchema(MetadataSchema::SCHEMAID_DEFAULT);

    # get Mailer templates for option lists
    $Mailer = $GLOBALS["G_PluginManager"]->getPlugin("Mailer");
    $TemplateOptions = $Mailer->GetTemplateList();

    $PossibleTreeFields = $ResourceSchema->GetFields(MetadataSchema::MDFTYPE_TREE);

    # load up all user interface options
    # use regex to filter out plugins' interfaces, more specifically,
    # drop interfaces whose path is "$PATH/$TO/$HERE/plugins/interface/$NAME"
    # i.e. the "interface" folder has a parent folder with the name "plugins"
    $UserInterfaceOptions = $GLOBALS["AF"]->GetUserInterfaces(
        "/^(?![a-zA-Z0-9\/]*plugins\/)[a-zA-Z0-9\/]*interface\/[a-zA-Z0-9%\/]+/"
    );

    # set up editing form
    $FormFields = [
        "HEADING-General" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "General",
        ],
        "PortalName" => [
            "Type" => FormUI::FTYPE_TEXT,
            "Label" => "Portal Name",
            "MaxLength" => 24,
            "Help" => "The name of the site as displayed in the"
                            ." title bar of the browser window and the page"
                            ." header above the navigation bar.",
        ],
        "AdminEmail" => [
            "Type" => FormUI::FTYPE_TEXT,
            "Label" => "Administrator Email",
            "Required" => true,
            "ValidateFunction" => ["Metavus\\FormUI", "ValidateEmail"],
            "Help" => "The email address of the individual responsible"
                            ." for overall site management. Feedback and other"
                            ." administrative mail is directed to this address.",
        ],
        "LegalNotice" => [
            "Type" => FormUI::FTYPE_TEXT,
            "Label" => "Legal Notice",
            "Help" => "Legal notice that may be displayed on some interfaces.",
        ],
        "SiteKeywords" => [
            "Type" => FormUI::FTYPE_PARAGRAPH,
            "Label" => "Site Keywords",
            "Help" => "Used by search engines to find your site."
                            ." Separate words and phrases by commas.",
        ],
            # -------------------------------------------------
        "HEADING-Features" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Features",
        ],
        "AnnouncementsEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Announcements",
            "Help" => "Whether the <i>Announcements</i> section"
                            ." on the home page is displayed.",
        ],
        "ResourceRatingsEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Resource Ratings/Recommendations",
            "Help" => "Whether <i>resource ratings</i> are "
                            ."enabled and displayed on the site."
        ],
        "IncrementalKeywordSearchEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Incremental Keyword Search",
            "Help" => "Whether users see an incremental "
                            ."keyword search (AKA search-as-you-type) "
                            ."interface to interactively show a subset "
                            ."of search results for the current search "
                            ."string when performing a keyword search "
                            ."from the keyword search box."
        ],
            # -------------------------------------------------
        "HEADING-Interface" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Interface",
        ],
        "NumAnnounceOnHomePage" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Announcements On Home Page",
            "MinVal" => 1,
            "Help" => "The maximum number of announcements "
                            ."that will be displayed on the home page "
                            ."if announcements are enabled."
        ],
        "NumResourcesOnHomePage" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Resources On Home Page",
            "MinVal" => 0,
            "Help" => "The maximum number of resources that "
                            ."will be displayed in the New Resources "
                            ."section on the home page."
        ],
        "ShowNumResourcesEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Display Resource Total On Home Page",
            "Help" => "Determines whether the total number "
                            ."of publicly-viewable resources is "
                            ."displayed on the home page."
        ],
        "DefaultActiveUI" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Default User Interface",
            "Options" => $UserInterfaceOptions,
            "Required" => true,
            "Help" => "Determines the user interface new "
                            ."members and logged-out users will view. "
                            ."Individual users may control this option "
                            ."for themselves through their preferences "
                            ."options if multiple interfaces are allowed "
                            ."by the site administrator. Selecting the "
                            ."Set All Users to This Interface checkbox "
                            ."will set each user's interface setting to "
                            ."the user interface selected."
        ],
        "ForceDefaultActiveUI" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Set All Users to Default Interface",
            "Help" => "When checked, this option will set all user"
                            ." accounts to the above Default User Interface.",
            "Value" => false,
        ],
        "AllowMultipleUIsEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Allow Multiple User Interfaces",
            "Help" => "Determines whether users may use a different "
                            ."user interface when logged in by selecting one "
                            ."in their preferences options. System "
                            ."Administrators may use different interfaces "
                            ."even if this option is disabled."
        ],
        "ResourceLaunchesNewWindowEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Resource Launches New Window",
            "Help" => "Determines if links to the Resource's URL "
                            ."(e.g., from the Full Record page or Search "
                            ."Results) will open in a new tab."
        ],
        "ShowGroupNamesEnabled" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Show Group Names In Full Record Page",
            "Help" => "Whether group names are shown in full record page."
        ],
        "PreferredLinkValue" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Preferred Link Value",
            "Help" => "Used when both <i>Resource URL Field</i> and"
                            ." <i>Resource File Field</i> are set, for records"
                            ." where both fields have values.",
            "Options" => ["URL" => "URL", "FILE" => "File"],
        ],
        "TitlesLinkTo" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Titles Link to",
            "Options" => ["URL" => "URL", "RECORD" => "Full Record"],
            "Help" => "Determines whether to use the resource's full "
                            ."record page or its URL when displaying links "
                            ."containing its title."
        ],
        "CollapseMetadataFieldGroups" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Collapse Metadata Field Groups",
            "Help" => "Determines whether metadata field groups "
                            ."created on the Metadata Field Ordering page "
                            ."should be collapsed by default when "
                            ."editing a resource."
        ],
        "RequireEmailWithFeedback" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Require Email Address with Feedback",
            "Help" => "Determines whether users who are not "
                            ."logged in are required to include an "
                            ."e-mail address when submitting feedback."
        ],
        "CommentsAllowHTML" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Resource Comments Allow HTML",
            "Help" => "Whether HTML is allowed in resource comments.",
        ],
            # -------------------------------------------------
        "HEADING-Browsing" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Browsing",
        ],
        "NumClassesPerBrowsePage" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Classifications Per Page When Browsing",
            "MinVal" => 2,
            "Help" => "The default number of classifications "
                            ."to display on the Browse Resources page "
                            ."before they are split up. System "
                            ."administrators should consider the size "
                            ."of the collection as well as the current "
                            ."state of browser technology as longer "
                            ."numbers of resource entries per page "
                            ."may require lengthy browser load times."
        ],
        "NumColumnsPerBrowsePage" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Columns Per Page When Browsing",
            "MinVal" => 1,
            "MaxVal" => 4,
            "RecVal" => 2,
            "Help" => "The number of columns in which to "
                            ."display the classifications on the "
                            ."Browse Resources page. (Minimum: "
                            ."<i>1</i>, Maximum: <i>4</i>, "
                            ."Recommended: <i>2</i>)"
        ],
        "BrowsingFieldId" => [
            "Type" => FormUI::FTYPE_METADATAFIELD,
            "Label" => "Default Browsing Field",
            "FieldTypes" => MetadataSchema::MDFTYPE_TREE,
            "SchemaId" => MetadataSchema::SCHEMAID_DEFAULT,
            "Required" => count($PossibleTreeFields) > 0 ? true : false,
            "Help" => "The default field displayed and used "
                            ."as the default browsing option on the "
                            ."Browse Resources page. This may be set "
                            ."to any tree field present in the "
                            ."metadata schema. While the field "
                            ."specified will be the default browsing "
                            ."option, users may choose to browse by "
                            ."any tree field they have "
                            ."permission to browse."
        ],
            # -------------------------------------------------
        "HEADING-Search" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Search",
        ],
        "SearchTermsRequired" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Default Search Term Handling",
            "Options" => [1 => "AND", 0 => "OR"],
            "Help" => "Determines whether AND or OR logic "
                            ."is used when more than one search "
                            ."term is specified. Resource records "
                            ."that contain all specified search "
                            ."terms will be retrieved when AND is "
                            ."selected. Resource records that have "
                            ."any of the search terms specified "
                            ."will be retrieved when OR is selected, "
                            ."but those that have two or more "
                            ."will be ranked higher."
        ],
        "DisplayLimitsByDefault" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "Display Search Limits by Default",
            "Help" => "Determines whether the search "
                            ."limits on the Advanced Search "
                            ."page are displayed or hidden "
                            ."by default."
        ],
        "DefaultRecordsPerPage" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Default Search Results Per Page",
            "Required" => true,
            "MinVal" => 5,
            "RecVal" => 10,
            "Help" => "Determines the default number "
                            ."of search results displayed per "
                            ."page. Users can override this "
                            ."setting from the User "
                            ."Preferences page."
        ],
        "MaxFacetsPerField" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Max Facets Per Field",
            "Help" => "The maximum number of facets to display "
                            ."per field in faceted search.",
            "Required" => true,
            "MinVal" => 2,
            "MaxVal" => 100,
            "RecVal" => 20,
        ],
            # -------------------------------------------------
        "HEADING-Metrics" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Metrics",
        ],
        "AddAWStatsScript" => [
            "Type" => FormUI::FTYPE_FLAG,
            "Label" => "AWStats Logging",
            "Help" => "Whether AWStats logging is performed."
        ],
            # -------------------------------------------------
        "HEADING-System" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "System",
        ],
        "MaxSimultaneousTasks" => [
            "Type" => FormUI::FTYPE_NUMBER,
            "Label" => "Maximum Simultaneous Background Tasks",
            "MinVal" => 1,
            "MaxVal" => 32,
            "Value" => $GLOBALS["AF"]->MaxTasks(),
            "Help" => "The maximum number of tasks to run in "
                            ."the background per execution cycle."
        ],
        "SearchEngineUpdatePriority" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Search Engine Update Task Priority",
            "Options" => $TaskPriorities,
            "Required" => true,
            "Help" => "The priority given to the tasks that "
                            ."run search engine updates for resources."
        ],
        "RecommenderEngineUpdatePriority" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Recommender Engine Update Task Priority",
            "Options" => $TaskPriorities,
            "Required" => true,
            "Help" => "The priority given to the tasks that "
                            ."run recommender engine updates for resources."
        ],
            # -------------------------------------------------
        "HEADING-UserAccounts" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "User Accounts",
        ],
        "DefaultUserPrivs" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Default New User Privileges",
            "AllowMultiple" => true,
            "Rows" => 15,
            "Options" => $PFactory->getPrivilegeOptions(),
            "Help" => "Determines the privilege flags that are "
                            ."given to users after they have "
                            ."registered for an account."
        ],
            # -------------------------------------------------
        "HEADING-Templates" => [
            "Type" => FormUI::FTYPE_HEADING,
            "Label" => "Mailer Templates",
        ],
        "PasswordChangeTemplateId" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Password Change Template",
            "Options" => $TemplateOptions,
        ],
        "EmailChangeTemplateId" => [
            "Type" => FormUI::FTYPE_OPTION,
            "Label" => "Email Change Template",
            "Options" => $TemplateOptions,
        ],
        "ActivateAccountTemplateId" => [
            "Type" => Formui::FTYPE_OPTION,
            "Label" => "Activate Account Template",
            "Options" => $TemplateOptions,
        ]
    ];

    # return form field info to caller
    return $FormFields;
}

/**
* Load values for form fields.
* @param array $FormFields Associative array of form field parameters, in
*       the format expected by FormUI.
* @return array Associative array of form field parameters, in the format
*       expected by FormUI, with field values filled in where available.
*/
function LoadFormValues($FormFields)
{
    $SysConfig = SystemConfiguration::getInstance();
    foreach ($FormFields as $FieldName => $FieldParams) {
        if ($FieldParams["Type"] == FormUI::FTYPE_HEADING) {
            continue;
        }
        unset($FieldValue);

        if (!isset($FormFields[$FieldName]["Value"])) {
            # retrieve field values from SystemConfiguration where available
            if ($SysConfig->fieldExists($FieldName)) {
                switch ($SysConfig->getFieldType($FieldName)) {
                    case SystemConfiguration::TYPE_ARRAY:
                        $FieldValue = $SysConfig->getArray($FieldName);
                        break;

                    case SystemConfiguration::TYPE_BOOL:
                        $FieldValue = $SysConfig->getBool($FieldName);
                        break;

                    case SystemConfiguration::TYPE_DATETIME:
                        $FieldValue = $SysConfig->getDatetime($FieldName);
                        break;

                    case SystemConfiguration::TYPE_INT:
                        $FieldValue = $SysConfig->getInt($FieldName);
                        break;

                    case SystemConfiguration::TYPE_STRING:
                    case SystemConfiguration::TYPE_EMAIL:
                    case SystemConfiguration::TYPE_IPADDRESS:
                    case SystemConfiguration::TYPE_URL:
                        $FieldValue = $SysConfig->getString($FieldName);
                        break;

                    case SystemConfiguration::TYPE_FLOAT:
                        $FieldValue = $SysConfig->getFloat($FieldName);
                        break;
                }
            } else {
                throw new Exception("Configuration setting for which value"
                        ." is not available (".$FieldName.").");
            }
        }

        if (isset($FieldValue)) {
            $FormFields[$FieldName]["Value"] = $FieldValue;
        }
    }

    return $FormFields;
}

/**
* Save values from form fields.
* @param array $NewSettings Associative array with field names for the index
*       and field values for the values.
*/
function SaveFormValues($NewSettings)
{
    $SysConfig = SystemConfiguration::getInstance();
    foreach ($NewSettings as $FieldName => $NewFieldValue) {
        switch ($FieldName) {
            case "ForceDefaultActiveUI":
                if ($NewFieldValue) {
                    # set all users to selected user interface
                    $UFactory = new UserFactory();
                    foreach ($UFactory->GetUserIds() as $UserId) {
                        $User = new User($UserId);
                        $User->Set("ActiveUI", $NewSettings["DefaultActiveUI"]);
                    }
                }
                break;

            case "MaxSimultaneousTasks":
                $GLOBALS["AF"]->MaxTasks($NewFieldValue, true);
                break;

            default:
                # save values via SystemConfiguration method if available
                if ($SysConfig->fieldExists($FieldName)) {
                    switch ($SysConfig->getFieldType($FieldName)) {
                        case SystemConfiguration::TYPE_ARRAY:
                            $SysConfig->setArray($FieldName, $NewFieldValue);
                            break;

                        case SystemConfiguration::TYPE_BOOL:
                            $SysConfig->setBool($FieldName, $NewFieldValue);
                            break;

                        case SystemConfiguration::TYPE_DATETIME:
                            $SysConfig->setDatetime($FieldName, $NewFieldValue);
                            break;

                        case SystemConfiguration::TYPE_INT:
                            $SysConfig->setInt($FieldName, (int) $NewFieldValue);
                            break;

                        case SystemConfiguration::TYPE_STRING:
                        case SystemConfiguration::TYPE_EMAIL:
                        case SystemConfiguration::TYPE_IPADDRESS:
                        case SystemConfiguration::TYPE_URL:
                            $SysConfig->setString($FieldName, $NewFieldValue);
                            break;

                        case SystemConfiguration::TYPE_FLOAT:
                            $SysConfig->setFloat($FieldName, (float) $NewFieldValue);
                            break;
                    }
                } else {
                    throw new Exception("New configuration value for which"
                            ." setting is not available (".$FieldName.").");
                }
                break;
        }
    }
}


# ----- MAIN -----------------------------------------------------------------

# check permissions
CheckAuthorization(PRIV_SYSADMIN, PRIV_COLLECTIONADMIN);

# set up form
$FormFields = DefineFormFields();

# load up current values for form fields
$FormFields = LoadFormValues($FormFields);

# instantiate form UI
$H_FormUI = new FormUI($FormFields);

# act on any button push
$ButtonPushed = StdLib::getFormValue("Submit");
switch ($ButtonPushed) {
    case "Save":
        # check values and bail out if any are invalid
        if ($H_FormUI->ValidateFieldInput()) {
            return;
        }

        # retrieve values from form
        $NewSettings = $H_FormUI->GetNewValuesFromForm();

        # save updated values
        SaveFormValues($NewSettings);

        # return to admin menu page
        $GLOBALS["AF"]->SetJumpToPage("SysAdmin");
        break;

    case "Cancel":
        # return to admin menu page
        $GLOBALS["AF"]->SetJumpToPage("SysAdmin");
        break;
}
